package common;

import ap.BDDACLWrapper;
import jdd.bdd.BDD;

import java.util.*;

import static ap.BDDACLWrapper.BDDFalse;

public class FIB implements Comparable<FIB>{
    public ForwardType type;
    public HashSet<String> forward;
    public int predicate;
    int prefixLen;
    long ip;

    public FIB(ForwardType t, String f, long ip, int prefix) {
        HashSet<String> fs = new HashSet<>();
        fs.add(f);
        type = t;
        forward = fs;
        this.ip = ip;
        this.prefixLen = prefix;
    }

    public FIB(FIB oldFIB,int newPredicate,HashSet<String> needNext) {   //更改
        type = oldFIB.type;
        forward = needNext;
        this.ip = oldFIB.ip;
        this.prefixLen = oldFIB.prefixLen;
        this.predicate=newPredicate;
    }

    public FIB(ForwardType t, HashSet<String> f, long ip, int prefix) {
        type = t;
        forward = f;
        this.ip = ip;
        this.prefixLen = prefix;
    }
    public FIB(ForwardType t, HashSet<String> f, int predicate) {
        type = t;
        forward = f;
        this.predicate = predicate;
    }
    public FIB(ForwardType t, String[] f, long ip, int prefix) {
        type = t;
        forward = new HashSet<>();
        forward.addAll(Arrays.asList(f));
        this.ip = ip;
        this.prefixLen = prefix;
    }
    public FIB() {
        forward = new HashSet<>();
    }
    public FIB(int predicate, String to){
        this();
        forward.add(to);
        this.predicate = predicate;
        this.type = ForwardType.ALL;
    }

    public FIB(FIB f) {
        type = f.type;
        forward = new HashSet<>(f.forward);
        ip = f.ip;
        prefixLen = f.prefixLen;
        predicate = f.predicate;
    }

    public int compareTo(FIB another_rule) {
        return this.prefixLen - another_rule.prefixLen;
    }


    public static void SortAndSetPredicate(Vector<FIB> fibs, BDDACLWrapper bddEngine) {
        BDD aclBDD = bddEngine.getBDD();
        synchronized (aclBDD){
            int alreadyFwd = BDDFalse;
            Collections.sort(fibs);
            for (int i=fibs.size()-1;i>=0;i--) {
                FIB f = fibs.get(i);
                int entryBdd = bddEngine.encodeDstIPPrefix(f.ip, f.prefixLen);
                int notAlreadyFwd = aclBDD.ref(aclBDD.not(alreadyFwd));
                int toAdd = aclBDD.ref(aclBDD.and(entryBdd, notAlreadyFwd));
                aclBDD.deref(notAlreadyFwd);
                alreadyFwd = aclBDD.orTo(alreadyFwd, entryBdd);
                aclBDD.deref(entryBdd);
                f.predicate = toAdd;
            }
            aclBDD.deref(alreadyFwd);
        }
    }

    public enum ForwardType {
        ANY, ALL, DROP
    }

    @Override
    public String toString() {
        return String.format("{%s, %s}", forward, predicate);
    }
}
